package com.leedsoft.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.reflect.TypeToken;
import com.leedsoft.common.Enums;
import com.leedsoft.common.JSON;
import com.leedsoft.common.Page;
import com.leedsoft.common.activiti.ActivitiHelper;
import com.leedsoft.controller.dto.*;
import com.leedsoft.controller.vo.AidPageVo;
import com.leedsoft.controller.vo.StepVo;
import com.leedsoft.controller.vo.TaskJsonVo;
import com.leedsoft.dao.TestDao;
import com.leedsoft.domain.*;
import com.leedsoft.mapper.*;
import com.leedsoft.mapper.self.AidPlanSelfMapper;
import com.leedsoft.mapper.self.AidSelfMapper;
import com.leedsoft.service.entity.ExpInfo;
import com.leedsoft.service.entity.Step;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

/**
 * Created by leeds on 2017/6/16.
 */
@Service
public class AidServiceImpl implements AidService {
    @Autowired
    private AidPlanMapper aidPlanMapper;
    @Autowired
    private AidPlanSelfMapper planSelfMapper;
    @Autowired
    private AidBpmSeqflowMapper flowMapper;
    @Autowired
    private AidTaskMapper taskMapper;
    @Autowired
    private AidSelfMapper selfMapper;
    @Autowired
    private ActivitiHelper activitiHelper;
    @Autowired
    private AidStepMapper stepMapper;
    @Autowired
    private AidBpmNodeMapper nodeMapper;
    @Autowired
    private TestDao testDao;

    @Override
    public void testDao() {
//        AidBpmNodeExample nodeExample = new AidBpmNodeExample();
//        nodeExample.createCriteria().andPlan_idEqualTo(3l);
//        List<AidBpmNode> nodes = nodeMapper.selectByExample(nodeExample);
//
//        AidBpmSeqflowExample flowExample = new AidBpmSeqflowExample();
//        flowExample.createCriteria().andPlan_idEqualTo(3l);
//        List<AidBpmSeqflow> flows = flowMapper.selectByExample(flowExample);
//
//        Map<String, Object> jsonMap = Maps.newHashMap();
//        jsonMap.put("nodes", nodes);
//
//        Map<Integer, List<AidBpmSeqflow>> nodeFlows = Maps.newHashMap();
//        for (AidBpmSeqflow flow : flows) {
//            if(!nodeFlows.containsKey(flow.getFrom())) {
//                List<AidBpmSeqflow> f = Lists.newArrayList();
//                f.add(flow);
//                nodeFlows.put(flow.getFrom(), f);
//            } else {
//                nodeFlows.get(flow.getFrom()).add(flow);
//            }
//        }
//        jsonMap.put("flows", nodeFlows);
//
//        System.out.println(JSON.gson.toJson(jsonMap));


        System.out.println(testDao.test());
    }

    @Override
    public Page<AidPlanDto> getAidPlanList(AidPageVo pageVo) {
        Page<AidPlanDto> page = new Page<>(pageVo);//获得page

//        int count = planSelfMapper.queryAidPlanListCount(pageVo);
//        page.setCount(count);
//        if (count != 0) {
//            List<AidPlanDto> planDtos = planSelfMapper.queryAidPlanList(pageVo);
//            page.setList(planDtos);
//        }
        return page;
    }

    @Override
    public AidPlan getAidPlan(Long planId) {
        return aidPlanMapper.selectByPrimaryKey(planId);
    }

    @Override
    public List<NodeDto> getNoOutNodes(Long planId) {
        List<NodeDto> res = Lists.newArrayList();
        //0节点
        AidBpmSeqflowExample seqflowExample = new AidBpmSeqflowExample();
        seqflowExample.createCriteria().andFromEqualTo(0)
                .andPlan_idEqualTo(planId);
        if (flowMapper.selectByExample(seqflowExample).size() == 0) {
            NodeDto node = new NodeDto();
            node.setCode(0);
            node.setSwitch_logic("");
            res.add(node);
        }
        //task 节点
        AidTaskExample taskExample = new AidTaskExample();
        taskExample.createCriteria().andPlan_idEqualTo(planId)
                .andHas_toEqualTo((short) 0);
        List<AidTask> tasks = taskMapper.selectByExample(taskExample);
        for (AidTask task : tasks) {
            NodeDto node = new NodeDto();
            node.setCode(task.getCode());
            node.setStepId(task.getStep_id());
            node.setSwitch_logic(StringUtils.isBlank(task.getSwitch_logic()) ? "通过" : task.getSwitch_logic());
            res.add(node);
        }
        Collections.sort(res, Comparator.comparingInt(NodeDto::getCode));
        return res;
    }

    @Override
    @Transactional
    public SaveStepDto saveStep(StepVo stepVo) {
        SaveStepDto res = new SaveStepDto();
        res.setOver(false);

        Step step = Step.getInstance(stepVo);
        step.build();
        if (stepVo.getType() == Enums.NodeType.OVER.getCode()) {//如果是结束节点
            List<NodeDto> nodes = getNoOutNodes(stepVo.getPlanId());
            if (nodes.size() == 0) {//当前流程图完整
                //启动activity 引擎，生成activity流程
                res.setOver(true);
                String procDefId = activitiHelper.genProcDef(stepVo.getPlanId());
                fillProcDefId(procDefId, stepVo.getPlanId());
                res.setProcDefId(procDefId);
            }
        }
        return res;
    }

    private void fillProcDefId(String procDefId, Long planId) {
        AidPlan plan = new AidPlan();
        plan.setId(planId);
        plan.setProcdef_id(procDefId);
        aidPlanMapper.updateByPrimaryKeySelective(plan);

        AidTask task = new AidTask();
        task.setProcdef_id(procDefId);
        AidTaskExample taskExample = new AidTaskExample();
        taskExample.createCriteria().andPlan_idEqualTo(planId);
        taskMapper.updateByExampleSelective(task, taskExample);
    }

    @Override
    public List<AidMemDto> getAidMems(Long planId) {
        List<AidMemDto> res = Lists.newArrayList();
        AidPlan plan = aidPlanMapper.selectByPrimaryKey(planId);
        if (plan != null) {
            res = selfMapper.queryAidMems(plan.getOrg_id());
        }
        return res;
    }

    @Override
    public List<StepDto> getSteps(Long planId) {
        Assert.notNull(planId);
        List<StepDto> res = Lists.newArrayList();

        AidStepExample stepExample = new AidStepExample();
        stepExample.setOrderByClause("id asc");
        stepExample.createCriteria().andPlan_idEqualTo(planId);
        List<AidStep> steps = stepMapper.selectByExample(stepExample);
        List<Long> stepIds = Lists.newArrayList();
        for (AidStep step : steps) {
            StepDto stepDto = new StepDto();
            BeanUtils.copyProperties(step, stepDto);
            stepIds.add(step.getId());
            res.add(stepDto);
        }

        if(stepIds.size() != 0) {
            AidTaskExample taskExample = new AidTaskExample();
            taskExample.createCriteria().andStep_idIn(stepIds);
            List<AidTask> tasks = taskMapper.selectByExample(taskExample);
            Map<Long, StepDto> stepMap = Maps.uniqueIndex(res, e -> e.getId());

            for (AidTask task : tasks) {
                StepDto step = stepMap.get(task.getStep_id());
                step.getNodes().add(task.getCode());
                if (task.getHas_to() == 0) {
                    step.getNoOutNodes().add(task.getCode());
                }
            }
        }
        return res;
    }

    @Override
    @Transactional
    public void delStep(Long stepId) {
        delStepWith(stepId);
        stepMapper.deleteByPrimaryKey(stepId);
    }

    @Override
    @Transactional
    public void delStepWith(Long stepId) {
        //del task
        AidTaskExample taskExample = new AidTaskExample();
        taskExample.createCriteria().andStep_idEqualTo(stepId);
        taskMapper.deleteByExample(taskExample);
        //del flows
        AidBpmNodeExample nodeExample = new AidBpmNodeExample();
        nodeExample.createCriteria().andStep_idEqualTo(stepId);
        List<Integer> nodeCodes = Lists.transform(nodeMapper.selectByExample(nodeExample), e -> e.getCode());

        AidBpmSeqflowExample flowExample = new AidBpmSeqflowExample();
        flowExample.createCriteria().andFromIn(nodeCodes);
        flowExample.or().andToIn(nodeCodes);
        flowMapper.deleteByExample(flowExample);
        //del nodes
        nodeMapper.deleteByExample(nodeExample);

        //update lastCodes
        AidStep step = stepMapper.selectByPrimaryKey(stepId);
        AidTask task = new AidTask();
        task.setHas_to((short)0);
        task.setTo_switch((short)0);
        taskExample.clear();
        taskExample.createCriteria().andPlan_idEqualTo(step.getPlan_id())
                .andCodeIn(Lists.transform(Arrays.asList(step.getLast_codes().split(",")), e -> Integer.parseInt(e)));
        taskMapper.updateByExampleSelective(task, taskExample);
    }

    @Override
    public StepInfoDto getStepInfo(Long stepId) {
        Assert.notNull(stepId);
        StepInfoDto res = new StepInfoDto();

        AidStep step = stepMapper.selectByPrimaryKey(stepId);
        Assert.notNull(step, stepId + "环节不存在");
        BeanUtils.copyProperties(step, res);

        if (!step.getType().equals(Enums.StepType.BRANCH.getCode())) {
            AidTaskExample taskExample = new AidTaskExample();
            taskExample.createCriteria().andStep_idEqualTo(stepId);
            List<AidTask> tasks = taskMapper.selectByExample(taskExample);
            List<TaskJsonVo> taskJsonVos = Lists.transform(tasks, input -> {
                TaskJsonVo taskJsonVo = new TaskJsonVo();
                BeanUtils.copyProperties(input, taskJsonVo);
                taskJsonVo.parseOperationCode();
                return taskJsonVo;
            });
            res.setTasks(taskJsonVos);
        } else {
            Map<Long, TaskJsonVo> taskMaps = Maps.newHashMap();
            List<Long> taskIds = Lists.newArrayList();
            List<ExpInfo> expInfoList = JSON.gson.fromJson(step.getExp_info(), new TypeToken<List<ExpInfo>>(){}.getType());
            for (ExpInfo expInfo : expInfoList) {
                TaskJsonVo taskJsonVo = new TaskJsonVo();
                taskJsonVo.setLabel(expInfo.getLabel());
                taskJsonVo.setExp(expInfo.getExp());
                taskJsonVo.setTaskType(expInfo.getType());
                taskMaps.put(expInfo.getTaskId(), taskJsonVo);

                taskIds.add(expInfo.getTaskId());
            }

            AidTaskExample taskExample = new AidTaskExample();
            taskExample.createCriteria().andIdIn(taskIds);
            List<AidTask> tasks = taskMapper.selectByExample(taskExample);
            for (AidTask task : tasks) {
                TaskJsonVo taskJsonVo = taskMaps.get(task.getId());
                BeanUtils.copyProperties(task, taskJsonVo);
            }
            res.setTasks(new ArrayList<>(taskMaps.values()));
        }
        return res;
    }

    @Override
    public List<NodeDto> getExistNodes(Long planId) {
        AidBpmNodeExample nodeExample = new AidBpmNodeExample();
        nodeExample.createCriteria().andPlan_idEqualTo(planId);
        List<AidBpmNode> nodes = nodeMapper.selectByExample(nodeExample);
        return Lists.transform(nodes, input -> {
            NodeDto node = new NodeDto();
            node.setStepId(input.getStep_id());
            node.setCode(input.getCode());
            return node;
        });
    }

    @Override
    public TaskJsonVo loadTask(Long planId, Integer taskCode) {
        TaskJsonVo res = new TaskJsonVo();
        AidTaskExample taskExample = new AidTaskExample();
        taskExample.createCriteria().andPlan_idEqualTo(planId).andCodeEqualTo(taskCode);
        List<AidTask> tasks = taskMapper.selectByExample(taskExample);
        if (tasks.size() > 0) {
            AidTask task = tasks.get(0);
            BeanUtils.copyProperties(task, res);
            res.parseOperationCode();
        }
        return res;
    }
}
